/////////////////////////////////////////////////////////////////////
//
//  icameraAppDelegate.m
//  OctaneMech
//
//  Created by Berlin Brown on 9/2/09.
//  Copyright __MyCompanyName__ 2009. All rights reserved.
//
//////////////////////////////////////////////////////////////////////

/*
 *  gluLookAt.h
 *
 *  This is a modified version of the function of the same name from 
 *  the Mesa3D project ( http://mesa3d.org/ ), which is  licensed
 *  under the MIT license, which allows use, modification, and 
 *  redistribution
 *
 *  In order to work under OpenGL ES, all instances of GLdouble
 *  had to be changed to GLfloat, and all "d" function calls had
 *  to be changed to the "f" versions.
 *
 *  Original developer's comments have been left in place.
 *
 *  Out of respect for the original authors, this is licensed under
 *  the Mesa (MIT) license. Original license follows:
 *  
 *  -----------------------------------------------------------------------
 *
 *  Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
 *  
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 *  BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 *  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#import "octanemechAppDelegate.h"
#import "EAGLView.h"
#import "Texture2D.h"

// define text variables
#define SCREEN_WIDTH  380
#define SCREEN_HEIGHT 320

#define NEAR   1
#define FAR    100
#define FOV    45
#define ASPECT  (float)SCREEN_WIDTH/(float)SCREEN_HEIGHT

#define kFontName       @"Arial"
#define kLabelFontSize  20

NSString   *testString;
Texture2D  *_textures[1];
int testVariable = 0;

#define kRenderingFrequency 60.0

typedef struct {
    GLfloat x;
    GLfloat y;
    GLfloat z;
} Vertex3D, Vector3D;

/**
 * Example usage: 
 *  gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f);
 */
void gluPerspective(double fovy, double aspect, double zNear, double zFar) {

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    double xmin, xmax, ymin, ymax;

    ymax = zNear * tan(fovy * M_PI / 360.0);
    ymin = -ymax;
    xmin = ymin * aspect;
    xmax = ymax * aspect;
    glFrustumf(xmin, xmax, ymin, ymax, 
                zNear, zFar);
  
    glMatrixMode(GL_MODELVIEW);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  

    glDepthMask(GL_TRUE);
} // End of the method 

void gluLookAt(GLfloat eyex,    GLfloat eyey,    GLfloat eyez,
               GLfloat centerx, GLfloat centery, GLfloat centerz,
               GLfloat upx,     GLfloat upy,     GLfloat upz) {
               
    GLfloat m[16];
    GLfloat x[3], y[3], z[3];
    GLfloat mag;
    
    /* Make rotation matrix */
    /* Z vector */
    z[0] = eyex - centerx;
    z[1] = eyey - centery;
    z[2] = eyez - centerz;
    mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
    if (mag) {          /* mpichler, 19950515 */
        z[0] /= mag;
        z[1] /= mag;
        z[2] /= mag;
    }
    
    /* Y vector */
    y[0] = upx;
    y[1] = upy;
    y[2] = upz;
    
    /* X vector = Y cross Z */
    x[0] =  y[1] * z[2] - y[2] * z[1];
    x[1] = -y[0] * z[2] + y[2] * z[0];
    x[2] =  y[0] * z[1] - y[1] * z[0];
    
    /* Recompute Y = Z cross X */
    y[0] =  z[1] * x[2] - z[2] * x[1];
    y[1] = -z[0] * x[2] + z[2] * x[0];
    y[2] =  z[0] * x[1] - z[1] * x[0];
    
    /* mpichler, 19950515 */
    /* cross product gives area of parallelogram, which is < 1.0 for
     * non-perpendicular unit-length vectors; so normalize x, y here
     */
    
    mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
    if (mag) {
        x[0] /= mag;
        x[1] /= mag;
        x[2] /= mag;
    }
    
    mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
    if (mag) {
        y[0] /= mag;
        y[1] /= mag;
        y[2] /= mag;
    }
    
#define M(row,col)  m[col*4+row]
    M(0, 0) = x[0];
    M(0, 1) = x[1];
    M(0, 2) = x[2];
    M(0, 3) = 0.0;
    M(1, 0) = y[0];
    M(1, 1) = y[1];
    M(1, 2) = y[2];
    M(1, 3) = 0.0;
    M(2, 0) = z[0];
    M(2, 1) = z[1];
    M(2, 2) = z[2];
    M(2, 3) = 0.0;
    M(3, 0) = 0.0;
    M(3, 1) = 0.0;
    M(3, 2) = 0.0;
    M(3, 3) = 1.0;
#undef M
    glMultMatrixf(m);
    
    /* Translate Eye to Origin */
    glTranslatef(-eyex, -eyey, -eyez);
    
} // End of glulookat //

// CLASS IMPLEMENTATION
@implementation AppController

- (void) renderText:(EAGLView*)view atPos:(float)pos  {

    glEnable(GL_TEXTURE_2D);
    CGPoint touchLoc = [view location];
    testString       = [NSString stringWithFormat: @"touch: %0.1f x=%0.1f y=%0.1f %x", pos, touchLoc.x, touchLoc.y, touchLoc];
    _textures[0]     = [[Texture2D alloc] initWithString:testString 
                                          dimensions:CGSizeMake(280, 30) 
                                           alignment:UITextAlignmentLeft 
                                            fontName:@"Arial" 
                                            fontSize:kLabelFontSize];
    
    ///////////////////////////////////////////// 
    // render our text
    /////////////////////////////////////////////
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(0, -48, -280);
    glColor4f(1, 1, 1, 1);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisable(GL_LIGHTING);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    [_textures[0] drawAtPoint:CGPointMake(0,0)];
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    glDisable(GL_BLEND);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);  
    glPopMatrix();
    [ _textures[0] release];
    glDisable(GL_TEXTURE_2D);
    
} // End of Method Render Text //

- (void) renderTextHUDForInput:(EAGLView*)view inType:(int)inType {

    testString   = [NSString stringWithFormat: @"input - %d", inType];
    _textures[0] = [[Texture2D alloc] initWithString:testString 
                                          dimensions:CGSizeMake(310, 36) 
                                           alignment:UITextAlignmentLeft 
                                            fontName:@"Arial" 
                                            fontSize:kLabelFontSize];
    
    ///////////////////////////////////////////// 
    // render our text
    /////////////////////////////////////////////
    glEnable(GL_TEXTURE_2D);
    glPushMatrix(); 
    glLoadIdentity();
  
    glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
    glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
    glTranslatef(180, -120, 0);
       
    glColor4f(1, 1, 1, 1);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisable(GL_LIGHTING);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    [_textures[0] drawAtPoint:CGPointMake(0, 0)];
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    glDisable(GL_BLEND);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);  
    glPopMatrix();
    [ _textures[0] release];
    glDisable(GL_TEXTURE_2D);
    
} // End of Method Render Text //

- (void) renderTextHUD:(EAGLView*)view {

    testString   = [NSString stringWithFormat: @"[octanemech-loaded]"];
    _textures[0] = [[Texture2D alloc] initWithString:testString 
                                          dimensions:CGSizeMake(310, 36) 
                                           alignment:UITextAlignmentLeft 
                                            fontName:@"Arial" 
                                            fontSize:kLabelFontSize];
    
    ///////////////////////////////////////////// 
    // render our text
    /////////////////////////////////////////////
    glEnable(GL_TEXTURE_2D);
    glPushMatrix(); 
    glLoadIdentity();
    
    glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
    glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
    glTranslatef(180, -80, 0);
       
    glColor4f(1, 1, 1, 1);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisable(GL_LIGHTING);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    [_textures[0] drawAtPoint:CGPointMake(0, 0)];
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    glDisable(GL_BLEND);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);  
    glPopMatrix();
    [ _textures[0] release];
    glDisable(GL_TEXTURE_2D);
    
} // End of Method Render Text //

- (void) renderInputGrid:(EAGLView*)view {

    GLfloat points_1[8] = {
        0.0f,   0.0f,       // Left
        30.0f,  0.0f,       // Right
        30.0f,  60.0f,      // Right Down
        0.0f,   60.0f       // Left Down
    };
    GLfloat points_2[8] = {
        0.0f,   0.0f,       // Left
        60.0f,  0.0f,       // Right
        60.0f,  20.0f,      // Right Down
        0.0f,   20.0f       // Left Down
    };
    
    glEnableClientState(GL_VERTEX_ARRAY);
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(0.0f, 210.0f, 0.0f);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    glVertexPointer (2, GL_FLOAT, 0, points_1); 
    // Also, use: GL_TRIANGLE_FAN or GL_LINE_LOOP
    glDrawArrays (GL_LINE_LOOP, 0, 4);
    glPopMatrix();
    
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(290.0f, 210.0f, 0.0f);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    glVertexPointer (2, GL_FLOAT, 0, points_1); 
    // Also, use: GL_TRIANGLE_FAN or GL_LINE_LOOP
    glDrawArrays (GL_LINE_LOOP, 0, 4);
    glPopMatrix();
    
    /////////////////////////////////////////////
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(130.0f, 22.0f, 0.0f);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    glVertexPointer (2, GL_FLOAT, 0, points_2); 
    // Also, use: GL_TRIANGLE_FAN or GL_LINE_LOOP
    glDrawArrays (GL_LINE_LOOP, 0, 4);
    glPopMatrix();
    
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(130.0f, 458.0f, 0.0f);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    glVertexPointer (2, GL_FLOAT, 0, points_2); 
    // Also, use: GL_TRIANGLE_FAN or GL_LINE_LOOP
    glDrawArrays (GL_LINE_LOOP, 0, 4);
    glPopMatrix();    
    
    ///////////////////////////////////////////////////////
    // Render the input grid for the
    // objects
    ///////////////////////////////////////////////////////
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(0.0f, 480.0f, 0.0f);
    glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
    glVertexPointer (2, GL_FLOAT, 0, points_1);
    glDrawArrays (GL_LINE_LOOP, 0, 4);
    glPopMatrix();
    
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(38.0f, 480.0f, 0.0f);
    glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
    glVertexPointer (2, GL_FLOAT, 0, points_1);
    glDrawArrays (GL_LINE_LOOP, 0, 4);
    glPopMatrix();

    glPushMatrix();
    glLoadIdentity();
    glTranslatef(4.0f, 290.0f, 0.0f);
    glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
    glVertexPointer (2, GL_FLOAT, 0, points_2); 
    glDrawArrays (GL_LINE_LOOP, 0, 4);
    glPopMatrix();
    
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(4.0f, 390.0f, 0.0f);
    glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
    glVertexPointer (2, GL_FLOAT, 0, points_2); 
    glDrawArrays (GL_LINE_LOOP, 0, 4);
    glPopMatrix();
      
    ///////////////
    // End of Input for the movement //
                
    glDisableClientState(GL_VERTEX_ARRAY);
}

- (void) renderCircle:(EAGLView*)view {
    
    glEnableClientState(GL_VERTEX_ARRAY);
    glPushMatrix();
    glLoadIdentity();
    CGFloat radius = 30.0f;
    CGFloat radius2 = 24.0f;
    const int segments = 60;
    const int segments2 = 20;
    GLfloat vertices[segments*2];
    GLfloat vertices2[segments2*2];
    int count = 0;
    
    glTranslatef(60.0f, 50.0f, 0.0);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);    
    for (GLfloat i = 0; i < 360.0f; i += (360.0f/segments)) {
        vertices[count++] = (cos(DEGREES_TO_RADIANS(i)) * radius);
        vertices[count++] = (sin(DEGREES_TO_RADIANS(i)) * radius);
    } // End of the For //

    glVertexPointer (2, GL_FLOAT, 0, vertices); 
    // Also, use: GL_TRIANGLE_FAN or GL_LINE_LOOP
    glDrawArrays (GL_LINE_LOOP, 0, segments);
    
    ///////////////////////////////////
    // Now, draw a sub circle
    /*
    glColor4f(1.0f, 0.0f, 0.0f, 0.7f); 
    count = 0;
    for (GLfloat z = -135; z < -40.0f; z += (360.0f / segments2)) {
        vertices2[count++] = (cos(DEGREES_TO_RADIANS(z)) * radius2);
        vertices2[count++] = (sin(DEGREES_TO_RADIANS(z)) * radius2);
    } // End of the For //
    glVertexPointer (2, GL_FLOAT, 0, vertices2); 
    // Also, use: GL_TRIANGLE_FAN or GL_LINE_LOOP
    glDrawArrays (GL_TRIANGLE_FAN, 0, segments2);    
    */
    
    glPopMatrix();
    glDisableClientState(GL_VERTEX_ARRAY);
}

- (void) renderHUD:(EAGLView*)view {
   
   /*
    <code>
    Example HUD matrix setup:
    glMatrixMode(GL_PROJECTION);           
    glLoadIdentity();                      
    glOrthof( 0, 480, 320, 0, 1, 0 );               
    glMatrixMode(GL_MODELVIEW);             
    glLoadIdentity();                   
    glDepthMask(GL_FALSE);
    </code>
    */
    CGPoint touchLoc = [view location];  
          
    /////////////////////////////////////////////
    // Enable 2d mode for hud title displays
    /////////////////////////////////////////////
    CGRect rect = view.bounds;
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();    // Push the projection matrix
    glLoadIdentity();
    glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
    
    glDisable(GL_LIGHTING);
    
    // Depth testing and lighting are disabled for 2D rendering until
    // we are finished rendering in 2D
    glDisable(GL_DEPTH_TEST);
    glDepthMask(GL_FALSE);
    /////////////////////////////////////////////
    /*
     * void glOrtho ( GLdouble left , GLdouble right , GLdouble bottom , 
     *                GLdouble top , GLdouble zNear , GLdouble zFar );
     */
    glOrthof(0, rect.size.height, rect.size.width, 0, 
            -1.0f, 1.0f); 

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();     // Push the model view matrix
    glLoadIdentity();
    /////////////////////////////////////////////
    
    // Render hud
    const GLfloat quadVertices2[] = {
        0.0f,    0.0f, 0.0f,   // negative left x, high, z zero
        10.0f,   0.0f, 0.0f,   // right x, high
        10.0f,   10.0f, 0.0f,   // right x, low
         0.0f,   10.0f, 0.0f    // negative x left, low
    };
    
    const GLfloat pointVert2[] = {
        0.0f,    0.0f, 0.0f,   // negative left x, high, z zero
        10.0f,   0.0f, 0.0f,   // right x, high
        10.0f,   10.0f, 0.0f,   // right x, low
         0.0f,   10.0f, 0.0f    // negative x left, low
    };
 
    glColor4f(1.0, 1.0, 1.0, 1.0);
    glEnableClientState(GL_VERTEX_ARRAY);
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(0.0f, 400.0f, 0.0f);
    glVertexPointer(3, GL_FLOAT, 0, quadVertices2); 
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    glPopMatrix();
    /////////////////////////////////////////////
    
    glColor4f(1.0, 0.0, 0.0, 1.0);       
    glPushMatrix();
    glLoadIdentity();
    glEnableClientState(GL_VERTEX_ARRAY);
    glTranslatef(touchLoc.x, touchLoc.y, 0.0f);
    glVertexPointer(3, GL_FLOAT, 0, pointVert2); 
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    glPopMatrix();
    
    /////////////////////////////////////////////
    [self renderInputGrid:view];
    [self renderCircle:view];
    
    glDisableClientState(GL_VERTEX_ARRAY);
   
    [self renderTextHUD:view];
    
    if (!hasInput && touchLoc.x > 120 && touchLoc.x < 200
        && touchLoc.y < 480 && touchLoc.y > 460) {
        
        [self renderTextHUDForInput:view inType:1];
        hasInput = TRUE;
    } else {    
        hasInput = FALSE;
    }
    
    /////////////////////////////////////////////
    // Disable 2d display
    /////////////////////////////////////////////
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix(); 
    glEnable(GL_LIGHTING);
            
} // End of the Method //

- (void) renderCircleGrid:(EAGLView*)view {
    
    const Vector3D normals [] = {
        0, 0, 1,
        0, 0, -1,
    };
    glNormalPointer(GL_FLOAT, 0, normals);
    
    const GLfloat quadVertices[] = {
        -0.2f,  0.2f, 0.0f,   // negative left x, high, z zero
         0.2f,  0.2f, 0.0f,   // right x, high
         0.2f, -0.2f, 0.0f,   // right x, low
        -0.2f, -0.2f, 0.0f    // negative x left, low
    };
    
    float radius = 18.0f;
    glPushMatrix();
    glLoadIdentity();
    for (float i = 0; i < 120.0f; i += 3.0f) {
        glLoadIdentity();
        float x = (cos(i) * radius);
        float y = (sin(i) * radius);
        glColor4f(1.0, 0.0, 1.0, 1.0);
        glTranslatef(x, 0.1f, y);
        glVertexPointer(3, GL_FLOAT, 0, quadVertices);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
        
    } // End of the for //
    glPopMatrix();
    
    // Render on the z axis
    glPushMatrix(); 
    for (float i = 0; i < 120.0f; i += 3.0f) {
        glLoadIdentity();
        float x = (cos(i) * radius);
        float y = (sin(i) * radius);
        glColor4f(1.0, 0.0, 0.0, 1.0);
        glTranslatef(0.0f, x, y);
        glVertexPointer(3, GL_FLOAT, 0, quadVertices);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
        
    } // End of the for //
    glPopMatrix();               
}

- (void) drawView:(EAGLView*)view {

    static GLfloat      rtri;                       // Angle For The Triangle ( NEW )
    static GLfloat      rquad;                      // Angle For The Quad     ( NEW )
    
    const GLfloat triVertices[] = { 
         0.0f,  1.0f, 0.0f, 
        -1.0f, -1.0f, 0.0f, 
         1.0f, -1.0f, 0.0f 
    }; 

    const GLfloat mechPoints[] = {
    
        -1.0f,  0.35f, -1.4f,   // negative left x, high, z zero
         1.0f,  0.35f, -1.4f,   // right x, high
         1.0f, -0.35f, -1.4f,   // right x, low
        -1.0f, -0.35f, -1.4f,   // negative x left, low
        
        -1.0f,  0.35f, -1.4f,   // Left Side
        -1.0f,  0.35f,  1.4f,
        -1.0f, -0.35f,  1.4f,
        -1.0f, -0.35f, -1.4f,             
       
       1.0f, -0.35f,  1.4f,
       -1.0f, -0.35f,  1.4f,
        -1.0f,  0.35f,  1.4f,   // Positive z side 
         1.0f,  0.35f,  1.4f,
         
         1.0f,  0.35f, -1.4f,   // Right side
         1.0f,  0.35f,  1.4f,
         1.0f, -0.35f,  1.4f,
         1.0f, -0.35f, -1.4f  
          
    };
     
    static const GLfloat cubeVertices[] = {
                -1.0f, 1.0f, 1.0f,
                1.0f, 1.0f, 1.0f,
                1.0f,-1.0f, 1.0f,
                -1.0f,-1.0f, 1.0f,
                -1.0f, 1.0f,-1.0f,
                1.0f, 1.0f,-1.0f,
                1.0f,-1.0f,-1.0f,
                -1.0f,-1.0f,-1.0f
        };
        static const GLubyte cubeNumberOfIndices = 36;

        const GLubyte cubeVertexFaces[] = {
                0, 1, 5, // Half of top face
                0, 5, 4, // Other half of top face

                4, 6, 5, // Half of front face
                4, 6, 7,    // Other half of front face

                0, 1, 2, // Half of back face
                0, 3, 2, // Other half of back face

                1, 2, 5, // Half of right face
                2, 5, 6, // Other half of right face

                0, 3, 4, // Half of left face
                7, 4, 3, // Other half of left face

                3, 6, 2, // Half of bottom face
                6, 7, 3, // Other half of bottom face

        };
        const GLubyte cubeFaceColors[] = {
                0,   255,   0, 255,
                255, 125,   0, 255,
                255,   0,   0, 255,
                255, 255,   0, 255,
                0,     0, 255, 255,
                255,   0, 255, 255
        };
    
    
    const GLfloat quadPlaneVertices[] = {
        -2.6f,  0.0f,  2.6f,  
        -2.6f,  0.0f, -2.6f,  // Far left position
         2.6f,  0.0f, -2.6f,  // Far right position
         2.6f,  0.0f,  2.6f
    };
    
    const Vector3D normals [] = {
        0, 0, 1,
        0, 0, -1,
    };
       
    const Vector3D normals3 [] = {
         0, 0, -1,
        -1, 0,  0,
         0, 0,  1,
         1, 0,  0,
    };
     
    const Vector3D normals2 [] = {
         0, 1, 0
    };     
     
    //glClear(GL_COLOR_BUFFER_BIT)    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    CGPoint touchLoc = [view location];
    /////////////////////////////////////////////////////////////////  
    if (touchLoc.x > 120 && touchLoc.x < 200
        && touchLoc.y < 480 && touchLoc.y > 460) {
        zcam += 0.1f;       
    } // End of the if //
    
    if (touchLoc.x > 120 && touchLoc.x < 200
        && touchLoc.y > 0 && touchLoc.y < 40) {
        zcam -= 0.1f;       
    } // End of the if //
    
    if (touchLoc.x > 0 && touchLoc.x < 60
        && touchLoc.y > 205 && touchLoc.y < 250) {
        xcam -= 0.1f;       
    } // End of the if //
    
    if (touchLoc.x > 280 && touchLoc.x < 480
        && touchLoc.y > 205 && touchLoc.y < 250) {
        xcam += 0.1f;       
    } // End of the if //
    /////////////////////////////////////////////////////////////////
    // Check the movement grid    
    if (touchLoc.x > 0 && touchLoc.x < 24
        && touchLoc.y > 320 && touchLoc.y < 380) {
        xbot_pos -= 0.05f;
    } // End of the if //
    
    if (touchLoc.x > 30  && touchLoc.x < 64
        && touchLoc.y > 320 && touchLoc.y < 380) {
        xbot_pos += 0.05f;
    } // End of the if //
     if (touchLoc.x > 10  && touchLoc.x < 64
        && touchLoc.y > 280 && touchLoc.y < 310) {
        zbot_pos -= 0.05f;
    } // End of the if //
    
    if (touchLoc.x > 10  && touchLoc.x < 64
        && touchLoc.y > 390 && touchLoc.y < 420) {
        zbot_pos += 0.05f;
    } // End of the if //
    
    // End of movement //    
    /////////////////////////////////////////////////////////////////

    glLoadIdentity();
    gluLookAt( 0.0f + xcam, 2.0f,  6.0f + zcam,
               0.0f, 0.0f,  0.0f,
               0.0f, 1.0f,  0.0f );
    glPushMatrix();  // Main Matrix for the Entire Scene //   
    glLoadIdentity();
    glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
    
    glEnableClientState(GL_NORMAL_ARRAY); 
    glNormalPointer(GL_FLOAT, 0, normals);  
    glPushMatrix();
    glTranslatef(-2.0f, 1.0f, -6.0f);
    glRotatef(rtri, 0.0f, 1.0f, 0.0f);
    glEnableClientState(GL_VERTEX_ARRAY);
    glColor4f(1.0f, 1.0f, 0.0f, 0.6f);
    glVertexPointer(3, GL_FLOAT, 0, triVertices);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
    glPopMatrix();
    
    //////////////////////////////////
    // Quad
    // Negative z with this camera view will move the
    // object backwards
    ///////////////////////////////////
    glNormalPointer(GL_FLOAT, 0, normals3);
    /*
    glPushMatrix();
    glColor4f(0.0, 0.0, 1.0, 1.0);
    glTranslatef(2.0f + xbot_pos, 1.0f, -10.0f + zbot_pos);
    glRotatef(rquad, 1.0f, 0.0f, 0.0f);
    glVertexPointer(3, GL_FLOAT, 0, mechPoints);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 16);
    glPopMatrix();
    */
    glEnable(GL_DEPTH_TEST);
    glPushMatrix();
    glTranslatef(2.0f + xbot_pos, 3.0f, -10.0f + zbot_pos);
    glRotatef(rquad, 0.0f, 1.0f, 0.0f);
    int colorIndex = 0;
    glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
    for (int i = 0; i < cubeNumberOfIndices; i += 3) {
           
        glColor4ub(cubeFaceColors[colorIndex], cubeFaceColors[colorIndex+1], cubeFaceColors[colorIndex+2], cubeFaceColors[colorIndex+3]);
        int face = (i / 3.0);
        if (face%2 != 0.0) {
            colorIndex+=4;
        }
        glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, &cubeVertexFaces[i]);
    }    
    glPopMatrix();
    glDisable(GL_DEPTH_TEST);
    
    ////////////////////////////////////////////////////////
    
    // Render the circle field //
    [self renderCircleGrid:view];
        
    ///////////////////////////////////////////////////////        
    // Render the plane
    glNormalPointer(GL_FLOAT, 0, normals2);
    glPushMatrix();
    glColor4f(0.7, 0.7, 0.7, 1.0);
    glTranslatef(0.0f, -1.0f, -4.0f);
    glScalef(3.0f, 1.0f, 3.0f);
    glVertexPointer(3, GL_FLOAT, 0, quadPlaneVertices);
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
    glPopMatrix();
    
    [self renderText:view atPos:rquad];
    
    /////////////////////////////////////////////////////////////////
    glPopMatrix();   // Pop the Matrix for the Entire Scene //
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    
    [self renderHUD:view];
    
    /////////////////////////////////////////////////////////////////
    
    static NSTimeInterval lastDrawTime;
    if (lastDrawTime) {
    
        NSTimeInterval timeSinceLastDraw = [NSDate timeIntervalSinceReferenceDate] - lastDrawTime;
        rtri += 20.0 * timeSinceLastDraw;    
        if (rtri > 360.0) {
            rtri -= 360.0;
        }
        
        rquad -= 15.0 * timeSinceLastDraw; 
        if (rquad < 0.0) {
            rquad += 360.0;
        }
    } // End of the if - time //
    lastDrawTime = [NSDate timeIntervalSinceReferenceDate];
         
} // End of Draw View Method //

static GLfloat no_mat[]         = { 0.0f, 0.0f, 0.0f, 1.0f };
static GLfloat mat_ambient[]    = { 0.9f, 0.9f, 0.9f, 1.0f };
static GLfloat mat_diffuse[]    = { 0.9f, 0.8f, 0.8f, 1.0f };
static GLfloat mat_specular[]   = { 0.0f, 1.0f, 1.0f, 1.0f };
static GLfloat no_shininess[]   = { 0.0f };
static GLfloat low_shininess[]  = { 5.0f };
static GLfloat high_shininess[] = { 100.0f};
static GLfloat mat_emission[]   = { 0.3f, 0.2f, 0.2f, 0.0f };

static GLfloat light_ambient[]  = { 0.1f, 0.1f, 0.1f, 0.1f };
static GLfloat light_diffuse[]  = { 1.0f, 1.0f, 1.0f, 0.0f };
static GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 0.0f };

//
// Materials
//
void setmaterial(float amb[], float diff[], float spec[],
                 float shine[], float emiss[]) {
                 
    glMaterialfv(GL_FRONT, GL_AMBIENT, amb);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, diff);
    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
    glMaterialfv(GL_FRONT, GL_SHININESS, shine);
    glMaterialfv(GL_FRONT, GL_EMISSION, emiss);
    
} // end of the function

void initMaterial(void) {

 // Change the main properities for all objects
 setmaterial(light_ambient, mat_diffuse, mat_specular, low_shininess, mat_emission);

} // end of the function 

/** 
 * Main setup the OpenGL view.
 */
-(void) setupView:(EAGLView*)view {

    const GLfloat   zNear       = 0.1,
                    zFar        = 1000.0,
                    fieldOfView = 60.0;
    GLfloat         size;        
    // Set the OpenGL projection matrix
    glMatrixMode(GL_PROJECTION);
    size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
    CGRect rect = view.bounds;
    glFrustumf( -size, size, 
                -size / (rect.size.width / rect.size.height), 
                 size / (rect.size.width / rect.size.height), 
                 zNear, zFar); 
    glViewport(0, 0, rect.size.width, rect.size.height);
 
    NSLog(@"[setupView] : width=%f height=%f", rect.size.width, rect.size.height);
              
    // Make the OpenGL modelview matrix the default
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
   
    /////////////////////////////////////////////
    // Texture, text setup.
    /////////////////////////////////////////////
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_TEXTURE_2D);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 
    NSString *testString = [NSString stringWithFormat: @"testing: %f", 0.0];
    // Initialize our texture with the text specified in testString
    _textures[0] = [[Texture2D alloc] initWithString:testString 
                        dimensions:CGSizeMake(140, 20) 
                         alignment:UITextAlignmentLeft 
                          fontName:@"Arial" 
                          fontSize:kLabelFontSize];
    glBindTexture(GL_TEXTURE_2D, [_textures[0] name]);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);   // Linear Filtered
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);   // Linear Filtered      
    // End of graphics text setup //
    
    initMaterial();
   
    // Enable Lighting
    GLfloat light_pos[4];
    light_pos[0] = 8.0f;
    light_pos[1] = 14.0f;
    light_pos[2] = 8.0f;
    light_pos[3] = 1.0f;
    
    glLightfv(GL_LIGHT0, GL_POSITION, light_pos); 
    glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
    glEnable(GL_LIGHT0);
    
    glEnable(GL_LIGHTING);
    
    // enable color tracking
    glEnable(GL_COLOR_MATERIAL);
    // set material properties which will be assigned by glColor
    
} // End of the Method //

/////////////////////////////////////////////////////////////////////

- (void) applicationDidFinishLaunching:(UIApplication*)application {

    CGRect rect = [[UIScreen mainScreen] bounds];
    
    //Create a full-screen window
    window = [[UIWindow alloc] initWithFrame:rect];
    
    //Create the OpenGL ES view and add it to the window
    EAGLView *glView = [[EAGLView alloc] initWithFrame:rect];
    [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
    [window addSubview:glView];

    glView.delegate = self;
    glView.animationInterval = 1.0 / kRenderingFrequency;
    [glView startAnimation];

    [glView release];
    
    //Show the window
    [window makeKeyAndVisible];
    
}

- (void) dealloc {

    [window release];
    [super dealloc];
}

@end // End of Impl AppController //
